package com.rockcent.api.controller;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rockcent.api.Routes;
import com.rockcent.common.common.JsonResult;
import com.rockcent.common.common.RestDoing;
import com.rockcent.common.controller.BaseController;
import com.rockcent.common.domain.enumclass.Whether;
import com.rockcent.common.utils.RBeanUtils;
import com.rockcent.helper.AuthResourceHelper;
import com.rockcent.mall.lib.domain.*;
import com.rockcent.mall.lib.domain.enumclass.SystemType;
import com.rockcent.mall.lib.dto.AuthResourceDto;
import com.rockcent.mall.lib.repository.*;
import com.rockcent.service.AuthUserResourceSrv;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by DK on 17/3/10.
 * 菜单管理
 */
@RestController
@RequestMapping(value = Routes.API_VERSION)
public class AuthResourceController extends BaseController{
    private final Logger log = LoggerFactory.getLogger(AuthResourceController.class);

    @Autowired
    private AuthResourceRepository authResourceRepository;

    @Autowired
    private AuthTitleResourceRepository authTitleResourceRepository;

    @Autowired
    private AuthUserResourceRepository authUserResourceRepository;

    @Autowired
    private AuthUserResourceSrv authUserResourceSrv;

    @Autowired
    private MallRepository mallRepository;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private AuthUserResourceDefaultRepository authUserResourceDefaultRepository;

    @Autowired
    private MerchantRepository merchantRepository;

    /**
     * @api {get} /v1/auth/resource/list 菜单列表
     * @apiGroup AUTH_RESOURCE
     *
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {String=ADMIN("R端"),MALL("M端"),MERCHANT("B端")} systemType <code>必须参数</code> 系统类型
     * @apiParam {long} id 菜单ID
     *
     * @apiSuccess {long} id 菜单ID
     * @apiSuccess {long} parentId 父ID
     * @apiSuccess {long} sort 顺序
     * @apiSuccess {String} iconName 图标名称
     * @apiSuccess {String} name 菜单名称
     * @apiSuccess {String} frontendUrl 前端url
     * @apiSuccess {String} backendUrl 后端url
     * @apiSuccess {String=ADMIN("R端"),MALL("M端"),MERCHANT("B端")} systemType 系统类型
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功",
     *      "data" :[
     *                   {
     *                   "id": 5,
     *                   "dateCreated": "2017-03-14 18:58:37",
     *                   "lastUpdated": "2017-03-14 18:58:37",
     *                   "iconName": "菜单1级",
     *                   "name": "菜单1级",
     *                   "sort": 1,
     *                   "systemType": "ADMIN",
     *                   "backendUrl": "http://baidu.com/",
     *                   "authResourceList": [
     *                          {
     *                          "id": 6,
     *                          "dateCreated": "2017-03-14 18:59:25",
     *                          "lastUpdated": "2017-03-14 18:59:25",
     *                          "parentId": 5,
     *                          "iconName": "菜单2级",
     *                          "name": "菜单2级",
     *                          "sort": 1,
     *                          "systemType": "ADMIN",
     *                          "backendUrl": "http://baidu.com/",
     *                          "authResourceList": []
     *                          },
     *                          {
     *                          "id": 7,
     *                          "dateCreated": "2017-03-15 11:56:24",
     *                          "lastUpdated": "2017-04-01 02:00:53",
     *                          "parentId": 5,
     *                          "iconName": "2级标题",
     *                          "name": "2级标题",
     *                           "*sort": 2,
     *                           "systemType": "ADMIN",
     *                           "backendUrl": "11111",
     *                           "authResourceList": [
     *                              {
     *                              "id": 8,
     *                              "dateCreated": "2017-03-15 11:58:18",
     *                              "lastUpdated": "2017-04-01 02:01:01",
     *                              "parentId": 7,
     *                              "iconName": "3级标题",
     *                              "name": "3级标题",
     *                              "sort": 3,
     *                              "systemType": "ADMIN",
     *                              "backendUrl": "11111",
     *                              "authResourceList": [
     *                                  {
     *                                  "id": 9,
     *                                  "dateCreated": "2017-03-15 13:48:11",
     *                                  "lastUpdated": "2017-04-01 02:01:12",
     *                                  "parentId": 8,
     *                                  "iconName": "4级标题",
     *                                  "name": "4级标题",
     *                                  "sort": 4,
     *                                  "systemType": "ADMIN",
     *                                  "backendUrl": "11111"
     *                                  },
     *                                  {
     *                                  "id": 10,
     *                                  "dateCreated": "2017-03-15 13:57:43",
     *                                  "lastUpdated": "2017-04-01 02:01:15",
     *                                  "parentId": 8,
     *                                  "iconName": "4级标题",
     *                                  "name": "4级标题",
     *                                  "sort": 5,
     *                                  "systemType": "ADMIN",
     *                                  "backendUrl": "/admin/user"
     *                                  }
     *                            ]
     *                       }
     *                 ]
     *           }
     *       ]
     *      }
     *    ]
     *   }
     */
    @RequestMapping(value = Routes.AUTH_RESOURCE_LIST, method = RequestMethod.GET)
    public JsonResult authResourceList (HttpServletRequest request, AuthResourceDto dto) {
        RestDoing doing = jsonResult -> {
            if (StringUtils.isBlank(dto.getSystemType()) || !EnumUtils.isValidEnum(SystemType.class, dto.getSystemType())) {
                jsonResult.remind("系统类型只允许 ADMIN(\"R端\"),MALL(\"M端\"),MERCHANT(\"B端\")",log);
                return;
            }
            List<AuthResourceDto> authResourceList = authResourceRepository.findAuthResourceDtoList(dto.getSystemType());
            for (AuthResourceDto resourceDto : authResourceList) {
                if (StringUtils.isNotBlank(resourceDto.getBackendUrl())) {
                    resourceDto.setBackendUrlList(objectMapper.readValue(resourceDto.getBackendUrl(), new TypeReference<List<String>>() {}));
                }else {
                    resourceDto.setBackendUrlList(new ArrayList<>());
                }
            }
            List<AuthResourceDto> topList = AuthResourceHelper.SINGLETON.createTree(null,authResourceList);
            jsonResult.data = topList;
        };
        return doing.go(request, log);
    }

    /**
     * @api {put} /v1/auth/resource/save 菜单保存
     * @apiGroup AUTH_RESOURCE
     *
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {String=ADMIN("R端"),MALL("M端"),MERCHANT("B端")} systemType <code>必须参数</code>系统类型
     * @apiParam {String} frontendUrl 前端url
     * @apiParam {list} backendUrlList 后端url集合
     * @apiParam {String} iconName <code>必须参数</code>标题
     * @apiParam {long} parentId 父级菜单id, <code>注:保存一级菜单时,值为空</code>
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功"
     *  }
     */
    @Transactional
    @RequestMapping(value = Routes.AUTH_RESOURCE_SAVE, method = RequestMethod.PUT)
    public JsonResult authResourceSave (HttpServletRequest request, @RequestBody AuthResourceDto dto) {
        RestDoing doing = jsonResult -> {
            String systemType = dto.getSystemType();
            if (StringUtils.isBlank(systemType)) {
                jsonResult.remind("系统类型 不能为空",log);
                return;
            }

            String dtoName = dto.getName();
            if (StringUtils.isBlank(dtoName)) {
                jsonResult.remind("标题 不能为空",log);
                return;
            }
            AuthResource authResource = new AuthResource();
            authResource.setName(dtoName);
            if (dto.getBackendUrlList() != null && dto.getBackendUrlList().size() > 0) {
                authResource.setBackendUrl(objectMapper.writeValueAsString(dto.getBackendUrlList()));
            }
            if (StringUtils.isNotBlank(dto.getFrontendUrl())) {
                authResource.setFrontendUrl(dto.getFrontendUrl());
            }
            if (dto.getParentId() != null) {
                authResource.setParentId(dto.getParentId());
            }
            authResource.setSystemType(SystemType.valueOf(systemType));
            Long maxSort = authResourceRepository.findMaxSortByParentId(dto.getParentId(), systemType);
            maxSort = maxSort == null ? 0L : maxSort;
            authResource.setSort(maxSort + 1L);
            authResource = authResourceRepository.save(authResource);
            AuthUserResourceDefault authUserResourceDefault = new AuthUserResourceDefault();
            authUserResourceDefault.setResourceId(authResource.getId());
            authUserResourceDefault.setResourceParentId(authResource.getParentId());
            authUserResourceDefault.setSystemType(SystemType.valueOf(systemType));
            authUserResourceDefaultRepository.save(authUserResourceDefault);
            //添加M端菜单,默认给所有M端添加此菜单
            if (authResource.getSystemType() == SystemType.MALL) {
                List<Mall> mallList = mallRepository.findAll();
                if (mallList.size() > 0) {
                    List<Long> resourceIdList = new ArrayList<>();
                    resourceIdList.add(authResource.getId());
                    for (Mall mall : mallList) {
                        authUserResourceSrv.updateAuthUserResourceWhenAddAuthResource(resourceIdList, mall.getUserInfoId(), mall.getId(), null);
                    }
                }
            }

            //添加M端菜单,默认给所有B端添加此菜单
            if (authResource.getSystemType() == SystemType.MERCHANT) {
                List<Merchant> merchantList = merchantRepository.findAll();
                if (merchantList.size() > 0) {
                    List<Long> resourceIdList = new ArrayList<>();
                    resourceIdList.add(authResource.getId());
                    for (Merchant merchant : merchantList) {
                        authUserResourceSrv.updateAuthUserResourceWhenAddAuthResource(resourceIdList, merchant.getUserInfoId(), merchant.getMallId(), merchant.getId());
                    }
                }
            }

        };
        return doing.go(request, log);
    }

    /**
     * @api {put} /v1/auth/resource/update 菜单更改
     * @apiGroup AUTH_RESOURCE
     *
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {long} id <code>必须参数</code>菜单ID
     * @apiParam {long} parentId 父级菜单id, <code>注:保存一级菜单时,值为空</code>
     * @apiParam {String=ADMIN("R端"),MALL("M端"),MERCHANT("B端")} systemType <code>必须参数</code>系统类型
     * @apiParam {String} frontendUrl 前端url
     * @apiParam {list} backendUrlList 后端url集合
     * @apiParam {String} iconName <code>可选参数</code>图标
     * @apiParam {String} name <code>必须参数</code>标题
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功"
     *  }
     */
    @Transactional
    @RequestMapping(value = Routes.AUTH_RESOURCE_UPDATE, method = RequestMethod.PUT)
    public JsonResult authResourceUpdate (HttpServletRequest request, @RequestBody AuthResourceDto dto) {
        RestDoing doing = jsonResult -> {
            if (dto.getId() == null) {
                jsonResult.remind(AuthResource.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            if (StringUtils.isBlank(dto.getName())) {
                jsonResult.remind("标题 不能为空",log);
                return;
            }
            AuthResource menu = authResourceRepository.findOne(dto.getId());
            if (menu == null) {
                jsonResult.remind(AuthResource.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }
            if (dto.getParentId() != null) {
                menu.setParentId(dto.getParentId());
            }
            if (dto.getSort() != null) {
                menu.setSort(dto.getSort());
            }
            if (dto.getBackendUrlList() != null && dto.getBackendUrlList().size() > 0) {
                menu.setBackendUrl(objectMapper.writeValueAsString(dto.getBackendUrlList()));
            }else {
                menu.setBackendUrl(null);
            }
            menu.setFrontendUrl(dto.getFrontendUrl());
            menu.setName(dto.getName());
            menu.setSystemType(SystemType.valueOf(dto.getSystemType()));
            authResourceRepository.save(menu);
        };
        return doing.go(request, log);
    }

    /**
     * @api {put} /v1/auth/resource/update_sort 菜单更改顺序
     * @apiGroup AUTH_RESOURCE
     *
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {long} id <code>必须参数</code> 菜单ID
     * @apiParam {long} resourceId <code>必须参数</code> 所占菜单位置的菜单ID
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功"
     *  }
     */
    @Transactional
    @RequestMapping(value = Routes.AUTH_RESOURCE_UPDATE_SORT, method = RequestMethod.PUT)
    public JsonResult authResourceUpdateSort (HttpServletRequest request, @RequestBody AuthResourceDto dto) {
        RestDoing doing = jsonResult -> {
            if (dto.getId() == null) {
                jsonResult.remind(AuthResource.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }

            AuthResource menu = authResourceRepository.findOne(dto.getId());
            if (menu == null) {
                jsonResult.remind(AuthResource.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }

            AuthResource subResource = authResourceRepository.findOne(dto.getResourceId());

            if (subResource.getParentId() != null) {
                List<AuthResource> authResourceList = authResourceRepository.findAuthResourceList(menu.getSystemType().toString(), menu.getId());
                List<AuthResource> resourceList = authResourceList.stream().filter(resource -> resource.getSort() >= subResource.getSort()).map(authResource -> authResource).collect(Collectors.toList());
                for (AuthResource resource : resourceList) {
                    resource.setSort(resource.getSort() + 1L);
                    authResourceRepository.save(resource);
                }
                menu.setParentId(subResource.getParentId());
            }

            menu.setSort(subResource.getSort());

            authResourceRepository.save(menu);
        };
        return doing.go(request, log);
    }

    /**
     * @api {get} /v1/auth/resource/info 菜单详情
     * @apiGroup AUTH_RESOURCE
     *
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {Long} resourceId <code>必须参数</code>菜单ID
     *
     * @apiSuccess {Long} id 菜单ID
     * @apiSuccess {Long} sort 菜单顺序
     * @apiSuccess {String} iconName 菜单名称
     * @apiSuccess {String=ADMIN("R端"),MALL("M端"),MERCHANT("B端")} systemType 系统类型
     * @apiSuccess {list} backendUrlList 后端url集合
     * @apiSuccess {String} frontendUrl 前端URL
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功",
     *      "data" {
     *                   "id": 5,
     *                   "iconName": "菜单1级",
     *                   "sort": 1,
     *                   "systemType": "ADMIN",
     *                   "backendUrl": "http://baidu.com/",
     *                   "frontendUrl": "http://baidu.com/"
     *      }
     *  }
     */
    @RequestMapping(value = Routes.AUTH_RESOURCE_INFO, method = RequestMethod.GET)
    public JsonResult authResourceInfo (HttpServletRequest request, Long resourceId) {
        RestDoing doing = jsonResult -> {
            if (resourceId == null) {
                jsonResult.remind(AuthResource.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }

            AuthResource authResource = authResourceRepository.findOne(resourceId);
            if (authResource == null) {
                jsonResult.remind(AuthResource.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }
            AuthResourceDto dto = new AuthResourceDto();
            RBeanUtils.copyProperties(authResource, dto);
            if (StringUtils.isNotBlank(authResource.getBackendUrl())) {
                dto.setBackendUrlList(objectMapper.readValue(authResource.getBackendUrl(), new TypeReference<List<String>>() {
                }));
            }
            jsonResult.data = dto;
        };
        return doing.go(request, log);
    }

    /**
     * @api {put} /v1/auth/resource/delete 菜单删除
     * @apiGroup AUTH_RESOURCE
     *
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {long} id <code>必须参数</code>菜单ID
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功"
     *  }
     */
    @Transactional
    @RequestMapping(value = Routes.AUTH_RESOURCE_DELETE, method = RequestMethod.PUT)
    public JsonResult authResourceDelete (HttpServletRequest request, @RequestBody AuthResourceDto dto) {
        RestDoing doing = jsonResult -> {
            if (dto.getId() == null) {
                jsonResult.remind(AuthResource.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            AuthResource authResource = authResourceRepository.findOne(dto.getId());
            if (authResource == null) {
                jsonResult.remind(AuthResource.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }

            //删除子菜单
            this.delete(authResource.getId());

            //删除职称的中间表
            List<AuthTitleResource> authTitleResourceList = authTitleResourceRepository.findByResourceIdAndIsDelete(authResource.getId(), Whether.NO);
            if (authTitleResourceList != null) {
                for (AuthTitleResource authTitleResource : authTitleResourceList) {
                    authTitleResourceRepository.delete(authTitleResource.getId());
                }
            }

            //删除用户中间表
            List<AuthUserResource> authUserResourceList = authUserResourceRepository.findByResourceIdAndIsDelete(authResource.getId(), Whether.NO);
            if (authUserResourceList != null) {
                for (AuthUserResource authUserResource : authUserResourceList) {
                    authUserResourceRepository.delete(authUserResource.getId());
                }
            }
            authResourceRepository.delete(authResource.getId());
        };
        return doing.go(request, log);
    }

    //递归删除子菜单
    @Transactional(propagation = Propagation.REQUIRED)
    public void delete (Long resourceId) {
        List<AuthResource> authResourceList = authResourceRepository.findByParentId(resourceId);
        if (authResourceList != null) {
            for (AuthResource resource : authResourceList) {
                delete(resource.getId());
            }
            authResourceRepository.delete(authResourceList);
        }
    }

}
